home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_503 / pcq / pcq12asc.lzh / Source / Utilities.p < prev   
Text File  |  1991-04-19  |  17KB  |  797 lines

  1. external;
  2.  
  3. {
  4.     Utilities.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid.
  6.  
  7.     This module handles the various tables and whatever
  8.     run-time business the compiler might have.
  9. }
  10.  
  11. {$O-}
  12. {$I "Pascal.i"}
  13. {$I "Include:Utils/StringLib.i"}
  14. {$I "Include:Utils/Break.i"}
  15.  
  16.     Procedure Error(s : string);
  17.         external;
  18.     Procedure NextSymbol;
  19.         external;
  20.     Procedure Abort;
  21.         external;
  22.     Procedure PushLongD0;
  23.         external;
  24.     Procedure PushLongD1;
  25.         External;
  26.     Procedure PopLongD1;
  27.         external;
  28.     Procedure PopLongD0;
  29.         External;
  30.     Procedure WriteHex(num : Integer);
  31.         External;
  32.  
  33.  
  34. Procedure NewSpell;
  35. var
  36.     TempPtr : SpellRecPtr;
  37. begin
  38.     New(TempPtr);
  39.     TempPtr^.Previous := CurrentSpellRec;
  40.     CurrentSpellRec := TempPtr;
  41.     CurrentSpellRec^.First := SpellPtr;
  42. end;
  43.  
  44. Procedure BackUpSpell(Position : Integer);
  45. var
  46.     TempPtr : SpellRecPtr;
  47. begin
  48.     while Position < CurrentSpellRec^.First do begin
  49.     TempPtr := CurrentSpellRec^.Previous;
  50.     Dispose(CurrentSpellRec);
  51.     CurrentSpellRec := TempPtr;
  52.     end;
  53.     SpellPtr := Position;
  54. end;
  55.  
  56. Function EnterSpell(S : String) : String;
  57. var
  58.     Length : Integer;
  59.     Result : String;
  60. begin
  61.     Length := strlen(S) + 1;
  62.     if (Length + SpellPtr) - CurrentSpellRec^.First > Spell_Max then
  63.     NewSpell;
  64.     Result := Adr(CurrentSpellRec^.Data[SpellPtr - CurrentSpellRec^.First]);
  65.     strcpy(Result, S);
  66.     SpellPtr := SpellPtr + Length;
  67.     EnterSpell := Result;
  68. end;
  69.  
  70.  
  71. Procedure Inc_NextCode;
  72. begin
  73.     Inc(NextCode);
  74.     if NextCode > MaxCode then begin
  75.     Error("Procedure too long (code table full)");
  76.     Abort;
  77.     end;
  78. end;
  79.  
  80. Procedure Out_Operation0(op : OpCodes);
  81. begin
  82.     Code_Table^[NextCode] := (Ord(op) shl 24) or ((2 shl 16) or
  83.                 (Ord(ea_None) shl 12) or (Ord(a7) shl 8) or
  84.                 (Ord(ea_None) shl 4) or Ord(a7));
  85.     Inc_NextCode;
  86. end;
  87.  
  88. Procedure Out_Operation1(op : OpCodes; Size : Byte;
  89.              EA : EAModes; Reg : Regs);
  90. begin
  91.     Code_Table^[NextCode] := (Ord(op) shl 24) or (Pred(Size) shl 16) or
  92.                 (Extensions[EA] shl 18) or
  93.                 (Ord(EA) shl 12) or (Ord(Reg) shl 8) or
  94.                 ((Ord(ea_None) shl 4) or Ord(a7));
  95.     Inc_NextCode;
  96. end;
  97.  
  98. Procedure Out_Operation2(op : OpCodes; Size : Byte;
  99.              SrcEA : EAModes; SrcReg : Regs;
  100.              DestEA: EAMOdes; DestReg: Regs);
  101. begin
  102.     Code_Table^[NextCode] := (Ord(op) shl 24) or (Pred(Size) shl 16) or
  103.                 ((Extensions[SrcEA] + Extensions[DestEA]) shl 18) or
  104.                 (Ord(SrcEA) shl 12) or (Ord(SrcReg) shl 8) or
  105.                 (Ord(DestEA) shl 4) or Ord(DestReg);
  106.     Inc_NextCode;
  107. end;
  108.  
  109. Procedure Out_Extension(Ext : Integer);
  110. begin
  111.     Code_Table^[NextCode] := Ext;
  112.     Inc_NextCode;
  113. end;
  114.  
  115. Procedure WriteRegisterList(Mask : Integer);
  116. var
  117.     Reg      : Regs;
  118.     WroteAny : Boolean;
  119. begin
  120.     WroteAny := False;
  121.     for Reg := d0 to a6 do begin
  122.     if (Mask and (1 shl Ord(Reg))) <> 0 then begin
  123.         if WroteAny then
  124.         Write(OutFile, '/')
  125.         else
  126.         WroteAny := True;
  127.         Write(OutFile, RN[Reg]);
  128.     end;
  129.     end;
  130. end;
  131.  
  132. Procedure WriteEA(EA : EAModes; Reg : Regs; Pos : Integer);
  133. var
  134.     ID : IDPtr;
  135.     Ext : Integer;
  136. begin
  137.     Ext := Code_Table^[Pos];
  138.     case EA of
  139.       ea_Constant : Write(OutFile, '#', Ext);
  140.       ea_Absolute : Write(OutFile, Ext);
  141.       ea_Literal  : Write(OutFile, '#_p%1+', Ext);
  142.       ea_Global   : begin
  143.             ID := IDPtr(Ext);
  144.             if ID^.Level <= 1 then
  145.                 Write(OutFile, '_', ID^.Name)
  146.             else
  147.                 Write(OutFile, '_', ID^.Name, '%', ID^.Unique);
  148.             end;
  149.       ea_Address  : begin
  150.             ID := IDPtr(Ext);
  151.             if ID^.Level <= 1 then
  152.                 Write(OutFile, '#_', ID^.Name)
  153.             else
  154.                 Write(OutFile, '#_', ID^.Name,'%',ID^.Unique);
  155.             end;
  156.       ea_Index    : Write(OutFile, Ext, '(', RN[Reg], ')');
  157.       ea_String   : Write(OutFile, String(Ext));
  158.       ea_Label    : Write(OutFile, '_p%', Ext);
  159.       ea_RegInd   : Write(OutFile, Ext shr 8, '(', RN[Reg], ',',
  160.                     RN[Regs(Ext and 15)], '.l)');
  161.       ea_RegList  : WriteRegisterList(Ext);
  162.       ea_Offset   : begin
  163.             ID := IDPtr(Ext);
  164.             if ID^.Level <= 1 then
  165.                 Write(OutFile, '#_', ID^.Name)
  166.             else
  167.                 Write(OutFile, '#_', ID^.Name, '%', ID^.Unique);
  168.             Write(OutFile, '+', Code_Table^[Succ(Pos)]);
  169.             end;
  170.       ea_Indirect : Write(OutFile, '(', RN[Reg], ')');
  171.       ea_PostInc  : Write(OutFile, '(', RN[Reg], ')+');
  172.       ea_PreDec   : Write(OutFile, '-(', RN[Reg], ')');
  173.       ea_Register : Write(OutFile, RN[Reg]);
  174.       ea_None     : ;
  175.     end;
  176. end;
  177.  
  178. Procedure FlushCodeTable;
  179. var
  180.     Code    : Integer;
  181.     Temp    : Integer;
  182.     Op      : OpCodes;
  183.     Size    : Byte;
  184.     SrcEA,
  185.     DestEA  : EAModes;
  186.     SrcReg,
  187.     DestReg : Regs;
  188.     UsedRegs: Integer;
  189. begin
  190.     Code     := 0;
  191.     UsedRegs := 0;
  192.     while Code < NextCode do begin
  193.     Temp   := Code_Table^[Code];
  194.  
  195.     case OpCodes(Temp shr 24) of
  196.       op_LINK,
  197.       op_UNLK : ;
  198.     else
  199.         UsedRegs := UsedRegs or (1 shl ((Temp shr 8) and 15))
  200.                  or (1 shl (Temp and 15));
  201.     end;
  202.  
  203.     Code := Succ(Code + ((Temp shr 18) and 3));
  204.     end;
  205.     UsedRegs := UsedRegs and $2CFC; { a5/a3/a2/d7/d6/d5/d4/d3/d2 }
  206.  
  207.     Code := 0;
  208.     while Code < NextCode do begin
  209.     Temp := Code_Table^[Code];
  210.     Op     := OpCodes(Temp shr 24);
  211.     Size   := Succ((Temp shr 16) and 3);
  212.     SrcEA  := EAModes((Temp shr 12) and 15);
  213.     SrcReg := Regs((Temp shr 8) and 15);
  214.     DestEA := EAModes((Temp shr 4) and 15);
  215.     DestReg:= Regs(Temp and 15);
  216.  
  217.     case Op of
  218.       op_LABEL :
  219.             begin
  220.             WriteEA(SrcEA,SrcReg,Succ(Code));
  221.             Writeln(OutFile);
  222.             Op := op_None;
  223.             end;
  224.  
  225.       op_LINK : if (UsedRegs and $2000) = 0 then
  226.             Op := op_None;
  227.  
  228.       op_POP :  begin
  229.             Op      := op_MOVE;
  230.             DestEA  := SrcEA;
  231.             DestReg := SrcReg;
  232.             SrcEA   := ea_PostInc;
  233.             SrcReg  := a7;
  234.             end;
  235.       op_PUSH : begin
  236.             Op      := op_MOVE;
  237.             DestEA    := ea_PreDec;
  238.             DestReg := a7;
  239.             end;
  240.       op_Save : begin
  241.             if (UsedRegs and $0CFC) <> 0 then begin
  242.                 Write(OutFile, '\tmovem.l\t');
  243.                 WriteRegisterList(UsedRegs and $0CFC);
  244.                 Writeln(OutFile, ',-(sp)');
  245.             end;
  246.             op := op_None;
  247.             end;
  248.       op_RESTORE :
  249.             begin
  250.             if (UsedRegs and $0CFC) <> 0 then begin
  251.                 Write(OutFile, '\tmovem.l\t(sp)+,');
  252.                 WriteRegisterList(UsedRegs and $0CFC);
  253.                 Writeln(OutFile);
  254.             end;
  255.             op := op_None;
  256.             end;
  257.       op_UNLK : if (UsedRegs and $2000) = 0 then
  258.             Op := op_None;
  259.     end;
  260.  
  261.     if Op <> op_None then begin
  262.         Write(OutFile, '\t', OpText[Op]);
  263.         case Size of
  264.           1 : Write(OutFile, '.b');
  265.           2 : Write(OutFile, '.w');
  266.           4 : Write(OutFile, '.l');
  267.         end;
  268.  
  269.         if SrcEA <> ea_None then begin
  270.         Write(OutFile, '\t');
  271.         WriteEA(SrcEA,SrcReg,Succ(Code));
  272.         end;
  273.         if DestEA <> ea_None then begin
  274.         Write(OutFile, ',');
  275.         WriteEA(DestEA,DestReg,Succ(Code + Extensions[SrcEA]));
  276.         end;
  277.  
  278.     {    Write(OutFile, '\t;');
  279.         WriteHex(Temp); }
  280.  
  281.         Writeln(OutFile);
  282.     end;
  283.     Code := Succ(Code + Extensions[SrcEA] + Extensions[DestEA]);
  284.     end;
  285. end;
  286.  
  287.  
  288. Function BaseType(orgtype : TypePtr): TypePtr;
  289.  
  290. {
  291.     This routine returns the base type of type.  If this
  292. routine is used consistently, ranges and subtypes will work with
  293. some consistency.
  294. }
  295.  
  296. begin
  297.     while (orgtype^.Object = ob_subrange) or (orgtype^.Object = ob_synonym) do
  298.     orgtype := orgtype^.SubType;
  299.     basetype := orgtype;
  300. end;
  301.  
  302. Function SimpleType(testtype : TypePtr) : Boolean;
  303.  
  304. {
  305.     If a variable passes this test, it is held in a register
  306. during processing.  If not, the address of the variable is held in
  307. the register.  This is the main reason why type conversions don't
  308. work across all types of the same size.
  309. }
  310.  
  311. begin
  312.     TestType := BaseType(TestType);
  313.     SimpleType := (TestType^.Size <= 4) and
  314.           (TestType^.Size <> 3) and
  315.           (TestType^.Object <> ob_record) and
  316.           (TestType^.Object <> ob_array);
  317. end;
  318.  
  319. Function HigherType(typea, typeb : TypePtr): TypePtr;
  320.  
  321. {
  322.     This routine returns the more complex type of the two
  323. numeric types passed to it.  In other words a 32 bit integer is
  324. 'higher' than a 16 bit one.
  325. }
  326.  
  327. begin
  328.     if (TypeA = RealType) or (TypeB = RealType) then
  329.     HigherType := RealType;
  330.     if (typea = inttype) or (typeb = inttype) then
  331.     highertype := inttype;
  332.     if (typea = shorttype) or (typeb = shorttype) then
  333.     highertype := shorttype;
  334.     highertype := typea;
  335. end;
  336.  
  337. Procedure PromoteType(var from : TypePtr; other : TypePtr; reg : Short);
  338.  
  339. {
  340.     This routine extends reg as necessary to make the 'from'
  341. type equivalent to 'other'.
  342. }
  343.  
  344. var
  345.     totype : TypePtr;
  346. begin
  347.     from := basetype(from);
  348.     other := basetype(other);
  349.     totype := highertype(from, other);
  350.     if from = totype then
  351.     return;
  352.     if totype = realtype then begin
  353.     if from^.Size = 1 then begin
  354.         Out_Operation2(op_AND,4,ea_Constant,a7,ea_Register,Regs(reg));
  355.         Out_Extension(255);
  356.     end else if from^.Size = 2 then
  357.         Out_Operation1(op_EXT,4,ea_Register,Regs(reg));
  358.     if reg = 0 then
  359.         PushLongD1
  360.     else begin
  361.         PushLongD0;
  362.         Out_Operation2(op_MOVE,4,ea_Register,d1,ea_Register,d0);
  363.     end;
  364.     Out_Operation2(op_MOVE,4,ea_String,a7,ea_Register,a6);
  365.     Out_Extension(Integer("_p%MathBase"));
  366.  
  367.     Out_Operation1(op_JSR,3,ea_Index,a6);
  368.     Out_Extension(-36);            { _LVOSPFlt }
  369.  
  370.     if reg = 0 then
  371.         PopLongD1
  372.     else begin
  373.         Out_Operation2(op_MOVE,4,ea_Register,d0,ea_Register,d1);
  374.         PopLongD0;
  375.     end;
  376.     from := RealType;
  377.     end else if totype = inttype then begin
  378.     if from^.Size = 2 then
  379.         Out_Operation1(op_EXT,4,ea_Register,Regs(Reg))
  380.     else if from^.Size = 1 then begin
  381.         Out_Operation2(op_AND,4,ea_Constant,a7,ea_Register,Regs(Reg));
  382.         Out_Extension(255);
  383.     end;
  384.     from := inttype;
  385.     end else if totype = shorttype then begin
  386.     if from^.Size = 1 then begin
  387.         Out_Operation2(op_AND,2,ea_Constant,a7,ea_Register,Regs(reg));
  388.         Out_Extension(255);
  389.     end;
  390.     from := shorttype;
  391.     end;
  392. end;
  393.  
  394. Procedure NewBlock;
  395. var
  396.     CB : BlockPtr;
  397.     i  : Short;
  398. begin
  399.     New(CB);
  400.     CB^.FirstType := Nil;
  401.     for i := 0 to Hash_Size do
  402.     CB^.Table[i] := Nil;
  403.     if CurrentBlock = Nil then
  404.     CB^.Level := 0
  405.     else
  406.     CB^.Level := Succ(CurrentBlock^.Level);
  407.     CB^.Previous := CurrentBlock;
  408.     CurrentBlock := CB;
  409. end;
  410.  
  411. Procedure KillIDList(ID : IDPtr);
  412. var
  413.     TempID : IDPtr;
  414. begin
  415.     while ID <> Nil do begin
  416.     if (ID^.Object = proc) or (ID^.Object = func) then
  417.         KillIDList(ID^.Param);
  418.     TempID := ID^.Next;
  419.     Dispose(ID);
  420.     ID := TempID;
  421.     end;
  422. end;
  423.  
  424. Procedure KillBlock;
  425. var
  426.     CB : BlockPtr;
  427.     ID : IDPtr;
  428.     TP : TypePtr;
  429.     i  : Integer;
  430.  
  431.     Procedure KillTypeList(TP : TypePtr);
  432.     var
  433.     TempType : TypePtr;
  434.     begin
  435.     while TP <> nil do begin
  436.         if TP^.Object = ob_record then
  437.         KillIDList(TP^.Ref);
  438.         TempType := TP^.Next;
  439.         Dispose(TP);
  440.         TP := TempType;
  441.     end;
  442.     end;
  443.  
  444. begin
  445.     CB := CurrentBlock;
  446.     CurrentBlock := CurrentBlock^.Previous;
  447.     for i := 0 to Hash_Size do
  448.     KillIDList(CB^.Table[i]);
  449.     KillTypeList(CB^.FirstType);
  450. end;
  451.  
  452. Function Match(sym : Symbols): Boolean;
  453.  
  454. {
  455.     If the current symbol is sym, return true and get the
  456. next one.
  457. }
  458.  
  459. begin
  460.     if CurrSym = Sym then begin
  461.     NextSymbol;
  462.     Match := True;
  463.     end else
  464.     Match := False;
  465. end;
  466.  
  467. {
  468.     The following routines just print out common error messages
  469. and make some common tests.
  470. }
  471.  
  472. procedure Mismatch;
  473. begin
  474.     error("Mismatched types");
  475. end;
  476.  
  477. procedure NeedNumber;
  478. begin
  479.     error("Expecting a numeric expression");
  480. end;
  481.  
  482. procedure NoLeftParent;
  483. begin
  484.     error("No left parenthesis");
  485. end;
  486.  
  487. procedure NoRightParent;
  488. begin
  489.     error("No right parenthesis");
  490. end;
  491.  
  492. Procedure UsingSmallStartup;
  493. begin
  494.     Error("This command is not supported by small startup code");
  495. end;
  496.  
  497. procedure NeedLeftParent;
  498. begin
  499.     if not match(leftparent1) then
  500.     noleftparent;
  501. end;
  502.  
  503. procedure NeedRightParent;
  504. begin
  505.     if not match(rightparent1) then
  506.     norightparent;
  507. end;
  508.  
  509. Procedure EnterID(EntryBlock : BlockPtr; ID : IDPtr);
  510. var
  511.     HVal : Short;
  512. begin
  513.     ID^.Level := EntryBlock^.Level;
  514.     HVal := Hash(ID^.Name) and Hash_Size;
  515.     ID^.Next := EntryBlock^.Table[HVal];
  516.     EntryBlock^.Table[HVal] := ID;
  517. end;
  518.  
  519. Function EnterStandard( st_Name : String;
  520.             st_Object : IDObject;
  521.             st_Type : TypePtr;
  522.             st_Storage : IDStorage;
  523.             st_Offset  : Integer)    : IDPtr;
  524. var
  525.     ID : IDPtr;
  526. begin
  527.     new(ID);
  528.     with ID^ do begin
  529.     Next    := Nil;
  530.     Name     := EnterSpell(st_Name);
  531.     Object    := st_Object;
  532.     VType    := st_Type;
  533.     Param    := Nil;
  534.     Storage    := st_Storage;
  535.     Offset    := st_Offset;
  536.     end;
  537.     EnterID(CurrentBlock, ID);
  538.     EnterStandard := ID;
  539. end;
  540.  
  541. Procedure ns;
  542.  
  543. {
  544.     This routine just tests for a semicolon.
  545. }
  546.  
  547. begin
  548.     if not match(semicolon1) then begin
  549.     if (currsym <> end1) and (currsym <> else1) and (currsym <> until1) then
  550.         error("missing semicolon");
  551.     end else
  552.     while match(semicolon1) do;
  553. end;
  554.  
  555. Function TypeCmp(TypeA, TypeB : TypePtr) : Boolean;
  556.  
  557. {
  558.     This routine just compares two types to see if they're
  559. equivalent.  Subranges of the same type are considered equivalent.
  560. Note that 'badtype' is actually a universal type used when there
  561. are errors, in order to avoid streams of errors.
  562. }
  563.  
  564. var
  565.     t1ptr,
  566.     t2ptr  : IDPtr;
  567. begin
  568.     TypeA := BaseType(TypeA);
  569.     TypeB := BaseType(TypeB);
  570.  
  571.     if TypeA = TypeB then
  572.     TypeCmp := True;
  573.     if (TypeA = BadType) or (TypeB = BadType) then
  574.     TypeCmp := True;
  575.     if TypeA^.Object <> TypeB^.Object then
  576.     typecmp := false;
  577.     if TypeA^.Object = ob_array then begin
  578.     if (TypeA^.Upper - TypeA^.Lower) <>
  579.        (TypeB^.Upper - TypeB^.Lower) then
  580.         typecmp := false;
  581.     TypeCmp := TypeCmp(TypeA^.Subtype, TypeB^.SubType);
  582.     end;
  583.     if TypeA^.Object = ob_pointer then
  584.     TypeCmp := TypeCmp(TypeA^.SubType, TypeB^.SubType);
  585.     if TypeA^.Object = ob_file then
  586.     TypeCmp := TypeCmp(TypeA^.SubType, TypeB^.Subtype);
  587.     TypeCmp := false;
  588. end;
  589.  
  590. Function NumberType(testtype : TypePtr) : Boolean;
  591.  
  592. {
  593.     Return true if this is a numeric type.
  594. }
  595.  
  596. begin
  597.     TestType := BaseType(TestType);
  598.     if TestType = IntType then
  599.     NumberType := true
  600.     else if TestType = ShortType then
  601.     NumberType := True
  602.     else if TestType = RealType then
  603.     NumberType := True
  604.     else if TestType = ByteType then
  605.     NumberType := True;
  606.     NumberType := False;
  607. end;
  608.  
  609. Function TypeCheck(TypeA, TypeB : TypePtr) : Boolean;
  610.  
  611. {
  612.     This is similar to typecmp, but considers numeric types
  613. equivalent.
  614. }
  615.  
  616. begin
  617.     TypeA := BaseType(TypeA);
  618.     TypeB := BaseType(TypeB);
  619.     if TypeA = TypeB then
  620.     TypeCheck := True;
  621.     if NumberType(TypeA) and NumberType(TypeB) then
  622.     TypeCheck := True;
  623.     TypeCheck := TypeCmp(TypeA, TypeB);
  624. end;
  625.  
  626. Function AddType(at_Object : TypeObject;
  627.          at_SubType: TypePtr;
  628.          at_Ref    : Address;
  629.          at_Upper,
  630.          at_Lower,
  631.          at_Size   : Integer) : TypePtr;
  632.  
  633. {
  634.     Adds a type to the id array.
  635. }
  636.  
  637. var
  638.     TP    : TypePtr;
  639. begin
  640.     New(TP);
  641.     with TP^ do begin
  642.     Object    := at_Object;
  643.     SubType    := at_SubType;
  644.     Ref     := at_Ref;
  645.     Upper    := at_Upper;
  646.     Lower    := at_Lower;
  647.     Size    := at_Size;
  648.     Next    := CurrentBlock^.FirstType;
  649.     end;
  650.     CurrentBlock^.FirstType := TP;
  651.     AddType := TP;
  652. end;
  653.  
  654. Function FindID(idname : string): IDPtr;
  655. { Find the most local reference to a variable }
  656. var
  657.     ID    : IDPtr;
  658.     CB  : BlockPtr;
  659.     HVal : Short;
  660. begin
  661.     CB := CurrentBlock;
  662.     HVal := Hash(idname) and Hash_Size;
  663.     while CB <> nil do begin
  664.     ID := CB^.Table[HVal];
  665.     while ID <> nil do begin
  666.         if strieq(idname, ID^.Name) then
  667.         FindID := ID;
  668.         ID := ID^.Next;
  669.     end;
  670.     CB := CB^.Previous;
  671.     end;
  672.     FindID := Nil;
  673. end;
  674.  
  675. Function CheckID(idname : string): IDPtr;
  676.  
  677. {
  678.     This is like the above, but only checks the current block.
  679. }
  680.  
  681. var
  682.     ID : IDPtr;
  683. begin
  684.     ID := CurrentBlock^.Table[Hash(idname) and Hash_Size];
  685.     while ID <> nil do begin
  686.     if strieq(idname, ID^.Name) then
  687.         CheckID := ID;
  688.     ID := ID^.Next;
  689.     end;
  690.     CheckID := Nil;
  691. end;
  692.  
  693. Function CheckIDList(S : String; ID : IDPtr) : Boolean;
  694. begin
  695.     while ID <> nil do begin
  696.     if strieq(S, ID^.Name) then
  697.         CheckIDList := True;
  698.     ID := ID^.Next;
  699.     end;
  700.     CheckIDList := False;
  701. end;
  702.  
  703. Function FindField(idname : string; RecType : TypePtr) : IDPtr;
  704.  
  705. {
  706.     This just finds the appropriate field, given the index of
  707. the record type.
  708.  
  709. }
  710.  
  711. var
  712.     ID    : IDPtr;
  713. begin
  714.     ID := RecType^.Ref;
  715.     while ID <> Nil do begin
  716.     if strieq(idname, ID^.Name) then
  717.         FindField := ID;
  718.     ID := ID^.Next;
  719.     end;
  720.     FindField := Nil;
  721. end;
  722.  
  723. Function FindWithField(Str : String) : IDPtr;
  724. var
  725.     CurrentWith : WithRecPtr;
  726.     ID : IDPtr;
  727. begin
  728.     CurrentWith := FirstWith;
  729.     while CurrentWith <> Nil do begin
  730.     ID := FindField(Str, CurrentWith^.RecType);
  731.     if ID <> Nil then begin
  732.         LastWith := CurrentWith;
  733.         FindWithField := ID;
  734.     end;
  735.     CurrentWith := CurrentWith^.Previous;
  736.     end;
  737.     FindWithField := Nil;
  738. end;
  739.  
  740. Function IsVariable(ID : IDPtr) : Boolean;
  741.  
  742. {
  743.     Returns true if index is a variable.
  744. }
  745.  
  746. begin
  747.     case ID^.Object of
  748.     local,
  749.     refarg,
  750.     valarg,
  751.     global,
  752.     typed_const,
  753.     field    : IsVariable := True;
  754.     else
  755.     IsVariable := False;
  756.     end;
  757. end;
  758.  
  759. Function Suffix(size : integer): char;
  760.  
  761. {
  762.     Returns the proper assembly language suffix for the various
  763. operations.
  764. }
  765.  
  766. begin
  767.     case Size of
  768.       1 : Suffix := 'b';
  769.       2 : Suffix := 'w';
  770.       4 : Suffix := 'l';
  771.     else
  772.         Suffix := '!'
  773.     end;
  774. end;
  775.  
  776.  
  777.  
  778. Function CompareProcs(Proc1, Proc2 : IDPtr) : Boolean;
  779. var
  780.     ID1, ID2 : IDPtr;
  781. begin
  782.     if Proc1^.Object <> Proc2^.Object then
  783.     CompareProcs := False;
  784.     if Proc1^.Object = func then
  785.     if not TypeCmp(Proc1^.VType, Proc2^.VType) then
  786.         CompareProcs := False;
  787.     ID1 := Proc1^.Param;
  788.     ID2 := Proc2^.Param;
  789.     while (ID1 <> Nil) and (ID2 <> Nil) do begin
  790.     if not TypeCmp(ID1^.VType, ID2^.VType) then
  791.         CompareProcs := False;
  792.     ID1 := ID1^.Next;
  793.     ID2 := ID2^.Next;
  794.     end;
  795.     CompareProcs := ID1 = ID2;
  796. end;
  797.